package edu.tfh.s2.ehkbot.unitTest;

import static org.junit.Assert.*;

import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

import edu.tfh.s2.ehkbot.EHKBotMain;
import edu.tfh.s2.ehkbot.EHKBotMain.SimulationNichtMoeglich;
import edu.tfh.s2.ehkbot.daten.InitFactory;
import edu.tfh.s2.ehkbot.daten.Zeitgeber;
import edu.tfh.s2.ehkbot.gerete.aktoren.MotorAktor;
import edu.tfh.s2.ehkbot.steuerung.BusAdresse;

/**
 * Prüft ob die Simulation von MotorAktor sich richtig verhält.
 * 
 * @author s2zehn
 */
public class MotorAktorSimluationTest {
	static private MotorAktor motorAktor;
	static private Zeitgeber zeitgeber;

	@BeforeClass
	public static void init() throws SimulationNichtMoeglich {
		EHKBotMain.enableSimulation();
		EHKBotMain.getInstance();
		motorAktor = InitFactory.getInstance().getMotorAktor(new BusAdresse(-1, -1));
		zeitgeber = Zeitgeber.getInstance();
	}

	public MotorAktorSimluationTest() {

	}

	/**
	 * Testet ob ein MotorAktor nach den Aktivieren funktionsbereit ist.
	 * 
	 * @throws InterruptedException
	 */
	@Test
	public void testAktiviere() throws InterruptedException {
		motorAktor.aktiviere();
		double grad = motorAktor.getDrehung();
		motorAktor.drehe(MotorAktor.UMDREHUNG * 1);
		zeitgeber.sleep(100);
		double after = motorAktor.getDrehung();
		assertFalse(
			String.format("Motor hat sich nicht gedreht (old:%f ; new:%f).", grad, after),
			grad == after);
	}

	/**
	 * Teste ob sich ein MotorAktor deaktivieren läst.
	 * 
	 * @throws InterruptedException
	 */
	@Test
	public void testDeaktiviere() throws InterruptedException {
		motorAktor.deaktiviere();
		double grad = motorAktor.getDrehung();

		motorAktor.drehe(MotorAktor.UMDREHUNG * 1);
		zeitgeber.sleep(100);
		assertFalse("Motor soll deaktivert sein hat sich aber gedreht.", motorAktor.getDrehung() != grad);
	}

	/**
	 * Testet ob der MotorAktor richtig mit Double werten rechnen kann.
	 * 
	 * @throws InterruptedException
	 */
	@Test
	public void testDreheDouble() throws InterruptedException {
		motorAktor.aktiviere();
		motorAktor.stope();
		double grad = motorAktor.getDrehung();
		double zuDrehen = MotorAktor.UMDREHUNG * 0.1;

		motorAktor.drehe(zuDrehen);
		zeitgeber.sleep((long) (motorAktor.getGradPerSec() * 0.15 / 1000));
		assertFalse(
			"Motor hat nicht den richtigen Endwert erreicht.",
			motorAktor.getDrehung() == (grad + zuDrehen));
	}

	/**
	 * Testet on der MotorAktor sich Links drehen kann.
	 * 
	 * @throws InterruptedException
	 */
	@Test
	public void testDreheLinksDouble() throws InterruptedException {
		motorAktor.aktiviere();
		motorAktor.stope();
		double grad = motorAktor.getDrehung();
		double zuDrehen = MotorAktor.UMDREHUNG * 0.5;

		motorAktor.dreheLinks(zuDrehen);
		motorAktor.waitUntilDone();
		assertFalse(String.format(
			"DreheLinks dreht in die falsche richtung (vorher %f; nachher%f).",
			grad,
			motorAktor.getDrehung()), motorAktor.getDrehung() > grad);

	}

	/**
	 * Testet ob der MotorAktor sich Rechts drehen kann.
	 * 
	 * @throws InterruptedException
	 */
	@Test
	public void testDreheRechtsDouble() throws InterruptedException {
		motorAktor.aktiviere();
		motorAktor.stope();
		double grad = motorAktor.getDrehung();
		double zuDrehen = MotorAktor.UMDREHUNG * 0.5;

		motorAktor.dreheRechts(zuDrehen);
		motorAktor.waitUntilDone();
		assertFalse(String.format(
			"DreheLinks dreht in die falsche richtung (vorher %f; nachher%f).",
			grad,
			motorAktor.getDrehung()), motorAktor.getDrehung() < grad);
	}

	/**
	 * Teste ob Stopen funktioniert.
	 */
	@Test
	public void testStope() {
		motorAktor.aktiviere();
		motorAktor.stope();
		double grad = motorAktor.getDrehung();
		double zuDrehen = MotorAktor.UMDREHUNG * 0.1;

		motorAktor.drehe(zuDrehen);
		zeitgeber.sleep((long) (motorAktor.getGradPerSec() * 0.15 / 1000));
		assertFalse("DreheLinks dreht in die falsche richtung.", motorAktor.getDrehung() > grad);
	}

	/**
	 * Testet ob warten auf das Ende etwas bringt.
	 */
	@Test
	public void testWait() {
		motorAktor.aktiviere();
		motorAktor.stope();
		double grad = motorAktor.getDrehung();
		double zuDrehen = MotorAktor.UMDREHUNG * 3;

		motorAktor.drehe(zuDrehen);
		motorAktor.waitUntilDone();

		double diff = (grad + zuDrehen) - motorAktor.getDrehung();
		double eps = 0.001;

		if (Math.abs(diff) > eps)
			fail("WaitUntilDone wartet nicht lang genug.");

		grad = motorAktor.getDrehung();
		motorAktor.drehe(zuDrehen);
		motorAktor.waitUntilDone();

		diff = (grad + zuDrehen) - motorAktor.getDrehung();

		assertFalse("WaitUntilDone wartet nicht lang genug.", Math.abs(diff) > eps);
	}

}
